package org.bronycorps.mlptss.utils;

import org.bronycorps.mlptss.domain.ai.DatedPolygon;

import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Polygon;
import com.badlogic.gdx.math.Vector2;

public class VectorUtils {
	public final static float SQRT_2 = (float) Math.sqrt(2);

	static final String TAG = VectorUtils.class.getSimpleName();

	/**
	 * Checks if both the vector's coordinates are inside the range [min,max],
	 * adjusting them if needed.
	 * <p>
	 * Returns <code>true</code> if at least one of the values was adjusted,
	 * <code>false</code> otherwise.
	 */
	public static boolean adjustByRange(Vector2 vector, float min, float max) {
		return adjustByRange(vector, min, max, min, max);
	}

	/**
	 * Checks if the vector's coordinates are inside the range [xMin,xMax] and
	 * [yMin,yMax], adjusting them if needed.
	 * <p>
	 * Returns <code>true</code> if at least one of the values was adjusted,
	 * <code>false</code> otherwise.
	 */
	public static boolean adjustByRange(Vector2 vector, float xMin, float xMax,
			float yMin, float yMax) {
		boolean modified = false;
		if (adjustByRangeX(vector, xMin, xMax)) {
			modified = true;
		}
		if (adjustByRangeY(vector, yMin, yMax)) {
			modified = true;
		}
		return modified;
	}

	/**
	 * Checks if the vector's X coordinate is inside the range [min,max],
	 * adjusting it if needed.
	 * <p>
	 * Returns <code>true</code> if the value was adjusted, <code>false</code>
	 * otherwise.
	 */
	public static boolean adjustByRangeX(Vector2 vector, float min, float max) {
		if (vector.x < min) {
			vector.x = min;
			return true;
		} else if (vector.x > max) {
			vector.x = max;
			return true;
		}
		return false;
	}

	/**
	 * Checks if the vector's Y coordinate is inside the range [min,max],
	 * adjusting it if needed.
	 * <p>
	 * Returns <code>true</code> if the value was adjusted, <code>false</code>
	 * otherwise.
	 */
	public static boolean adjustByRangeY(Vector2 vector, float min, float max) {
		if (vector.y < min) {
			vector.y = min;
			return true;
		} else if (vector.y > max) {
			vector.y = max;
			return true;
		}
		return false;
	}

	/**
	 * Uses the given value when the vector coordinates are less than or equal
	 * to the specified radius value.
	 */
	public static boolean adjustDeadzone(Vector2 vector, float radius,
			float adjustedValue) {
		if (vector.len() <= radius) {
			vector.x = adjustedValue;
			vector.y = adjustedValue;
			return true;
		}
		return false;
	}

	public static Vector2 calculateKnockBack(Vector2 target, Vector2 pusher,
			float power) {
		Vector2 finalPosition = new Vector2(target).sub(pusher);
		finalPosition.nor().mul(power);
		return finalPosition;
	}

	/**
	 * creates a rectangular polygon based on 2 points and the radius. The
	 * polygon is a rectangle rotated as a segment that joins the points. The
	 * polygon's origin is (0,0), no scaling nor rotation
	 * 
	 * @param p0
	 *            start point
	 * @param p1
	 *            end point
	 * @param radius
	 *            radius of the points, which is 1/2 the width of the rectangle.
	 * @return the polygon
	 */
	public static Polygon createOrientedRectangle(Vector2 p0, Vector2 p1,
			float radius) {

		final float angle = new Vector2(p1).sub(p0).angle();
		final float angle1 = angle - 135;
		final float angle2 = angle + 135;
		final float angle3 = angle - 45;
		final float angle4 = angle + 45;
		final float radius45 = SQRT_2 * radius;

		return new Polygon(new float[] {
				MathUtils.cosDeg(angle1) * radius45 + p0.x,
				MathUtils.sinDeg(angle1) * radius45 + p0.y,
				MathUtils.cosDeg(angle3) * radius45 + p1.x,
				MathUtils.sinDeg(angle3) * radius45 + p1.y,
				MathUtils.cosDeg(angle4) * radius45 + p1.x,
				MathUtils.sinDeg(angle4) * radius45 + p1.y,
				MathUtils.cosDeg(angle2) * radius45 + p0.x,
				MathUtils.sinDeg(angle2) * radius45 + p0.y });
	}

	/**
	 * creates a triangular polygon based on 2 points and the radius. The
	 * polygon is a triangle rotated as a segment that joins the points. The
	 * polygon's origin is (0,0), no scaling nor rotation
	 * 
	 * @param p0
	 *            base point
	 * @param p1
	 *            end point
	 * @param radius
	 *            radius of the points, which is 1/2 the width of the rectangle.
	 * @return the polygon
	 */
	public static DatedPolygon createOrientedTriangle(Vector2 p0, Vector2 p1,
			float radius) {

		final float angle = new Vector2(p1).sub(p0).angle();
		final float angle1 = angle - 135;
		final float angle2 = angle + 135;
		final float radius45 = SQRT_2 * radius;

		return new DatedPolygon(p0, p1, new float[] {
				MathUtils.cosDeg(angle1) * radius45 + p0.x,
				MathUtils.sinDeg(angle1) * radius45 + p0.y,
				MathUtils.cosDeg(angle) * radius + p1.x,
				MathUtils.sinDeg(angle) * radius + p1.y,
				MathUtils.cosDeg(angle2) * radius45 + p0.x,
				MathUtils.sinDeg(angle2) * radius45 + p0.y });
	}

}
